package com.hlkj.warboot.module_wx.configurer.Intercept;

import com.alibaba.fastjson.JSONObject;
import com.hlkj.warboot.configurer.properties.WxProperties;
import com.hlkj.warboot.configurer.util.*;
import com.hlkj.warboot.configurer.util.base.BaseWxAuthUtil;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.MessageFormat;

/**
 * @Description: TODO 微信活动.用户授权拦截器
 * @Author: 李星 lixing_java@163.com
 * @Date: 2020/2/20 20:39
 */
@Component
public class AuthIntercept implements HandlerInterceptor {
    private final WxProperties wxProperties;

    public AuthIntercept(WxProperties wxProperties) {
        this.wxProperties = wxProperties;
    }

    /**
     * @Description 前置拦截
     * @Author 李星
     * @Date 2020/2/20 20:43
     * @Param [request, response, handler]
     * @return boolean
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            BaseWxAuthUtil baseWxAuthUtil = handlerMethod.getMethodAnnotation(BaseWxAuthUtil.class); // TODO 获取自定义注解对象
            if (baseWxAuthUtil != null) {
                String currentReqUrl = RequestUtil.getRequestUrl(request);
                String errorUrl = RequestUtil.getBaseErrorUrl(request, "/wx/base/error");
                /*
                 * @Description TODO 是否微信客户端打开
                 */
                if (baseWxAuthUtil.isWxChat() && !UserAgentUtil.isWechat(request)) {
                    response.sendRedirect(errorUrl + "?code=1");
                    return false;
                }
                if (!baseWxAuthUtil.isWxChat()) {
                    return true;
                }
                //
                /*
                 * @Description TODO 用户授权
                 */
                String openid = (String) request.getSession().getAttribute("openid");
                if (StrUtil.isEffective(openid)) {
                    /*
                     * @Description TODO ====================================================================当前用户已发起授权
                     */
                    return true;
                } else {
                    /*
                     * @Description TODO ==================================================================当前用户还未发起授权
                     * 1、用户授权（静默授权、弹框授权），获取临时code
                     * 2、通过code换取网页授权access_token
                     * 3、拉取用户信息(需scope为 snsapi_userinfo)
                     */
                    String code = request.getParameter("code");
                    if (!StrUtil.isEffective(code)) {
                        // TODO 1、当前code无效，需发起用户授权来获取code临时凭证
                        // 以 snsapi_base 为scope发起的网页授权，是用来获取进入页面的用户的openid的，并且是静默授权并自动跳转到回调页的。用户感知的就是直接进入了回调页（往往是业务页面）
                        // 以 snsapi_userinfo 为scope发起的网页授权，是用来获取用户的基本信息的。但这种授权需要用户手动同意，并且由于用户同意过，所以无须关注，就可在授权后获取该用户的基本信息
                        // 授权成功后，页面将跳转至 redirect_uri/?code=CODE&state=STATE
                        String getCodeUrl = MessageFormat.format(
                                "https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state=STATE#wechat_redirect",
                                wxProperties.getTest_gzh_appid(), // TODO ★★★★ 生产环境请切到正式appid ★★★★
                                currentReqUrl,
                                "snsapi_userinfo");                         // TODO ★★★★ 生产环境请根据具体需求选择相应的收起模式 ★★★★
                        response.sendRedirect(getCodeUrl);
                        return false;
                    }

                    // TODO 2、通过code换取网页授权access_token、openid
                    // code作为换取access_token的票据，每次用户授权带上的code将不一样，code只能使用一次，5分钟未被使用自动过期
                    String getAccessTokenUrl = MessageFormat.format(
                            "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code",
                            wxProperties.getTest_gzh_appid(),               // TODO ★★★★ 生产环境请切到正式appid ★★★★
                            wxProperties.getTest_gzh_appsecret(),           // TODO ★★★★ 生产环境请切到正式appsecret ★★★★
                            code);
                    String resString = HttpHelperUtil.sendRequestHttps(getAccessTokenUrl, "POST", null);
                    JSONObject resJSON = JSONObject.parseObject(resString);
                    if (StrUtil.isEffective(resJSON.getString("errcode"))) {
                        LoggerUtil.error("通过code换取网页授权access_token失败：" + resJSON.getString("error"));
                        response.sendRedirect(errorUrl + "?code=2");
                        return false;
                    }

                    // TODO 3、拉取用户信息(需scope为 snsapi_userinfo)
                    String getUserInfoUrl = MessageFormat.format(
                            "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang=zh_CN",
                            resJSON.getString("access_token"),
                            resJSON.getString("openid")
                    );
                    resString = HttpHelperUtil.sendRequestHttps(getUserInfoUrl, "POST", null);
                    resJSON = JSONObject.parseObject(resString);
                    if (StrUtil.isEffective(resJSON.getString("errcode"))) {
                        LoggerUtil.error("通过access_token换取用户信息失败：" + resJSON.getString("error"));
                        response.sendRedirect(errorUrl + "?errMessage=3");
                        return false;
                    }

                    request.getSession().setAttribute("openid", resJSON.getString("openid")); // 用户的唯一标识
                    request.getSession().setAttribute("nickName", resJSON.getString("nickname")); // 用户昵称
                    request.getSession().setAttribute("cover", resJSON.getString("headimgurl")); // 用户头像
                    return true;
                }
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}
